﻿namespace MefContrib.Models.Provider
{
    using System;
    using System.Diagnostics;
    using System.Reflection;

    /// <summary>
    /// Provides an abstraction for working with a method on a reflection level.
    /// </summary>
    public class ComposableMethod : ComposableMember
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ComposableMethod"/> class
        /// for the specified <see cref="MemberInfo"/>.
        /// </summary>
        /// <param name="member">The member to make composable.</param>
        /// <exception cref="InvalidOperationException">The specified value for the member parameter was not a <see cref="MethodInfo"/> instance.</exception>
        public ComposableMethod(MemberInfo member)
            : base(member)
        {
            MethodInfo info = member as MethodInfo;
            if (info == null)
            {
                throw new InvalidOperationException("The specified value for the member parameter was not a MethodInfo instance.");
            }

            this.Method = info;

            this.ValueGetter =
                getInstance =>
                this.Method.CreateDelegate(getInstance);
        }

        /// <summary>
        /// Gets a value indicating whether or not type of the <see cref="ComposableMethod"/> is of a lazy type or not.
        /// </summary>
        /// <value><see langword="true" /> if it is of a known lazy type; otherwise <see langword="false" />.</value>
        public override bool IsLazyType
        {
            get { return this.ReturnType.IsLazyType(); }
        }

        /// <summary>
        /// Gets a value indicating whether or not a value can be retrieved from the member.
        /// </summary>
        /// <value><see langword="true" /> if a value can be retrieved; otherwise <see langword="false" />.</value>
        public override bool IsReadable
        {
            [DebuggerStepThrough]
            get { return true; }
        }

        /// <summary>
        /// Gets a value indicating whether or not an instance is needed for the value to be retrieved or assigned.
        /// </summary>
        /// <value><see langword="true" /> if an instance is needed; otherwise <see langword="false" />.</value>
        public override bool IsInstanceNeeded
        {
            [DebuggerStepThrough]
            get { return !this.Method.IsStatic; }
        }

        /// <summary>
        /// Gets a value indicating whether or not a value can be assigned to the member.
        /// </summary>
        /// <value><see langword="true" /> if a value can be assigned; otherwise <see langword="false" />.</value>
        public override bool IsWritable
        {
            [DebuggerStepThrough]
            get { return false; }
        }

        /// <summary>
        /// Gets the reference to the method.
        /// </summary>
        /// <value>A <see cref="MethodInfo"/> object.</value>
        public MethodInfo Method { get; protected set; }

        /// <summary>
        /// Gets the <see cref="Type"/> of the return value of the <see cref="ComposableType"/>.
        /// </summary>
        /// <value>A <see cref="Type"/> object.</value>
        public override Type ReturnType
        {
            [DebuggerStepThrough]
            get { return this.Method.ReturnType; }
        }
    }
}